package com.hczt.xhminiapp.adminapi.conf.security;

import com.hczt.xhminiapp.db.entity.OauthClientDetails;
import com.hczt.xhminiapp.db.repository.OauthClientDetailsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.*;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.*;

/**
 * @author 红创-马海强
 * @date 2019-04-01 13:01
 * @说明：
 */
@Component
public class Oauth2Config {

    private static final String ADMIN_RESOURCE_ID  = "app/manage";
    @Autowired
    private OauthClientDetailsRepository oauthClientDetailsRepository;

    /**
     * jwt加密串
     */
    @Value("${jwt.secretKey}")
    private String secretKey;

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(secretKey);
        return converter;
    }

    @Bean
    public TokenEnhancer jwtTokenEnhancer() {
        return (accessToken, authentication) -> {
            final Map<String, Object> additionalInfoMap = new HashMap<>();
            String clientId = authentication.getOAuth2Request().getClientId();
            Optional<OauthClientDetails> oauthClientDetails = oauthClientDetailsRepository.findById(clientId);
            oauthClientDetails.ifPresent(client -> {
                additionalInfoMap.put("appName", client.getClientName());
            });
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfoMap);
            return accessToken;
        };
    }

    /**
     * server config
     */
    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
        @Autowired
        private DataSource dataSource;
        @Autowired
        private TokenStore tokenStore;
        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired
        private JwtAccessTokenConverter jwtAccessTokenConverter;
        @Autowired
        private TokenEnhancer jwtTokenEnhancer;
        @Autowired
        private SysUserDetailsService sysUserDetailsService;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
            endpoints.authenticationManager(authenticationManager)
                    .tokenStore(tokenStore)
                    .accessTokenConverter(jwtAccessTokenConverter)
                    .userDetailsService(sysUserDetailsService)
                    .reuseRefreshTokens(false);

            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtTokenEnhancer, jwtAccessTokenConverter));
            endpoints.tokenEnhancer(tokenEnhancerChain);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
            oauthServer.checkTokenAccess("isAuthenticated()")  // 允许check_token
                    .allowFormAuthenticationForClients();   //允许表单登录
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.jdbc(dataSource);
        }
    }


    /**
     * 后台管理资源访问
     *
     * @return
     */
    @Bean
    protected ResourceServerConfiguration adminResources() {

        ResourceServerConfiguration resource = new ResourceServerConfiguration() {
            public void setConfigurers(List<ResourceServerConfigurer> configurers) {
                super.setConfigurers(configurers);
            }
        };

        resource.setConfigurers(Collections.singletonList(new ResourceServerConfigurerAdapter() {

            @Override
            public void configure(ResourceServerSecurityConfigurer resources) {
                resources.resourceId(ADMIN_RESOURCE_ID);
                resources.authenticationEntryPoint(new OAuthExceptionEntryPoint());
            }

            @Override
            public void configure(HttpSecurity http) throws Exception {
                http.antMatcher("/admin/**").authorizeRequests().anyRequest().authenticated();
            }

        }));
        resource.setOrder(1);

        return resource;

    }

}
